package com.classloader.config;


import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 样例：
 * 有一个jar包，最新版本为3.12.0 项目中正在使用
 * 这时候有一个新功能，需要3.11里的一个文件，
 * 这时候我们需要用自定义的类加载器，去加载3.11的类，从而实现
 *
 * @author yinxing
 * @date 2022-09-08
 */
public class MyClassLoader extends ClassLoader {

    private Map<String, byte[]> clazz;

    /**
     * * 将jar包中的class文件，存储到map中
     * key为class全路径名字，value为class的字节码
     *
     * @param files
     * @return
     * @throws IOException
     */
    public MyClassLoader(String... files) throws IOException {
        clazz = new HashMap<>();
        for (String file : files) {
            //解析文件 格式是xxx/ds/xxda/dfa/fdf.class  ==> com.das.cdcs.class
            JarFile jarFile = new JarFile(file);
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                if (jarEntry.getName().endsWith(".class")) {
                    try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
                        int pos = 0;
                        int len;
                        byte[] bytes = new byte[inputStream.available()];
                        while ((len = inputStream.read(bytes, pos, bytes.length - pos)) > 0) {
                            pos += len;
                        }
                        // /替换成.
                        String className = jarEntry.getName().replace("/", ".")
                                .replace(".class", "");
                        clazz.put(className, bytes);
                    }
                }
            }
        }
    }

    /**
     * 类加载器加载出来
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> loadedClass = findLoadedClass(name);
            //如果类加载器中没有拿到class文件
            if (loadedClass == null) {
                //先从自定义的类加载其中拿
                byte[] bytes = clazz.get(name);
                if (bytes == null) {
                    //从父类的类加载其中拿
                    super.loadClass(name, resolve);
                } else {
                    //从自定义的类加载中找到了class，
                    //将map中存好的字节码二进制转化为字节码文件
                    loadedClass = defineClass(name, bytes, 0, bytes.length);
                }
            }
            return loadedClass;
        }
    }


    public static void main(String[] args) {
//        test1();
        test2();
    }

    public static void test1() {
        System.out.println(getSystemClassLoader().getClass().getName());
        System.out.println(StringUtils.isEmpty("ss"));
    }

    public static void test2() {
        try {
            MyClassLoader classLoader =
                    new MyClassLoader("D:\\software\\jar\\commons-lang3-2.5.jar");
            Class<?> aClass = classLoader.loadClass("org.apache.commons.lang.StringUtils");
            Method isEmpty = aClass.getMethod("isEmpty", CharSequence.class);
            System.out.println(aClass.getClassLoader().getClass().getName());
            System.out.println(isEmpty.invoke(null, "11"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
